package pers.xx.sbm.utils.thread_resolve;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @author ：xiexing
 * @description：TODO
 * @date ：2020/9/7 10:45
 */
public class Demo2 {
    //文件的路径
    private String filePath;
    //文件名
    private String fileName;
    //文件大小
    private long length;
    //块数
    private int size;
    //每块的大小
    private long blockSize;
    //分割后的存放目录
    private String destBlockPath;
    //每块的名称
    private List<String> blockPath;

    public Demo2() {
        blockPath = new ArrayList<String>();
    }

    public Demo2(String filePath, String destBlockPath) {
        this(filePath, destBlockPath, 1024 * 1024 * 100);
    }

    public Demo2(String filePath, String destBlockPath, long blockSize) {
        this();
        this.filePath = filePath;
        this.destBlockPath = destBlockPath;
        this.blockSize = blockSize;
        init();
    }


    /**
     * @Description: 初始化操作 计算 块数、确定文件名
     * @Param: []
     * @return: void
     * @Author: hw
     * @Date: 2018/12/25
     */
    public void init() {
        File file = null;
        //如果为空或者路径为文件夹则返回
        if (filePath == null || !((file = new File(filePath)).exists()) || file.isDirectory())
            return;
        //文件名
        this.fileName = file.getName();
        //计算分割数量    实际大小    每块大小
        this.length = file.length();
        //每块大小
        if (this.blockSize > length) {
            this.blockSize = length;
        }
        //确定分割数量
        size = (int) Math.ceil(length * 1.0 / this.blockSize);
        //确定分割文件的路径
        initPathName();
    }

    private void initPathName() {
        for (int i = 0; i < size; i++) {
            this.blockPath.add(destBlockPath + "/" + this.fileName + ".part" + i);
        }
    }

    /**
     * 文件的分割
     * 0)、第几块
     * 1、起始位置
     * 2、实际大小
     * 分割文件存放目录
     */
    boolean exeFlag = true;

    public void split() {
        long beginPos = 0;  //起始点
        long actualBlockSize = blockSize; //实际大小
        //计算所有块的大小、位置、索引
        for (int i = 0; i < size; i++) {
            if (i == size - 1) { //最后一块
                actualBlockSize = length - beginPos;
            }

            spiltDetail(i, beginPos, actualBlockSize);
            //多线程版本
//            new Run(i,beginPos,actualBlockSize,filePath,blockPath).start();
            beginPos += actualBlockSize; //本次的终点，下一次的起点
        }
    }



    public static void main(String[] args) {
        //1024 * 30 表示按照每块30Kb大小分割
        final Demo2 split = new Demo2("D:/BaiduNetdiskDownload/123.mp4", "D:/BaiduNetdiskDownload/123/", 1024 * 200 * 1024);
        System.out.println(split.size);
        long l = System.currentTimeMillis();

        split.split();
//        split.merge("D:/BaiduNetdiskDownload/123/123.mp4");

    }

    /**
     * @Description: 文件分割
     * @Param: [idx, beginPos, actualBlockSize]
     * @return: void
     * @Author: hw
     * @Date: 2018/12/25
     */
    private void spiltDetail(int idx, long beginPos, long actualBlockSize) {
        //1、创建源
        File src = new File(this.filePath);  //源文件
        File dest = new File(this.blockPath.get(idx)); //目标文件
        //2、选择流
        RandomAccessFile raf = null;  //输入流
        BufferedOutputStream bos = null; //输出流
        try {
            raf = new RandomAccessFile(src, "r");
            bos = new BufferedOutputStream(new FileOutputStream(dest));
            //读取文件
            raf.seek(beginPos);
            //缓冲区
            byte[] flush = new byte[1024<<2];
            //接收长度
            int len = 0;
            while (-1 != (len = raf.read(flush))) {
                if (actualBlockSize - len >= 0) { //查看是否足够
                    //写出
                    bos.write(flush, 0, len);
                    actualBlockSize -= len; //剩余量
                } else { //写出最后一次的剩余量
                    bos.write(flush, 0, (int) actualBlockSize);
                    break;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            this.close(bos, raf);
        }
    }


    /**
     * 文件的合并
     */
    public void merge(String destPath) {
        //创建源
        File dest = new File(destPath);
        //选择流
        BufferedOutputStream bos = null; //输出流
        SequenceInputStream sis = null;//输入流
        //创建一个容器
        Vector<InputStream> vi = new Vector<InputStream>();
        try {
            for (int i = 0; i < this.blockPath.size(); i++) {
                vi.add(new BufferedInputStream(new FileInputStream(new File(this.blockPath.get(i)))));
            }
            bos = new BufferedOutputStream(new FileOutputStream(dest, true)); //追加
            sis = new SequenceInputStream(vi.elements());
            //缓冲区
            byte[] flush = new byte[1024<<2];
            //接收长度
            int len = 0;
            while (-1 != (len = sis.read(flush))) {
                bos.write(flush, 0, len);
            }
            bos.flush();
            this.close(sis);
        } catch (Exception e) {
        } finally {
            this.close(bos);
        }
    }

    //关闭流
    public static void close(Closeable... io) {
        for (Closeable temp : io) {
            try {
                if (null != temp) {
                    temp.close();
                }
            } catch (Exception e) {
            }
        }

    }

    /**
     * 使用泛型方法
     */
    public static <T extends Closeable> void closeAll(T... io) {
        for (Closeable temp : io) {
            try {
                if (null != temp) {
                    temp.close();
                }
            } catch (Exception e) {
            }
        }
    }


}
